package br.com.velp.sudecap.daoimpl;

import br.com.velp.sudecap.comum.SpringConstants;
import br.com.velp.sudecap.dao.GrupoUsuarioDAO;
import br.com.velp.sudecap.entidade.*;
import java.util.List;
import org.hibernate.*;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;

/**
 * <sumario>
 * <objetivo> "Rastreabilidade" </objetivo>
 * <autor> EDUARDO SANTOS DE OLIVEIRA </autor>
 * <versao>1.0.0.0</versao>
 * <data_criacao> 17.10.2012 </data_criacao>
 * <data_ultima_alteracao> N/A </data_ultima_alteracao>
 * <requisitos_afetados> RF010.05 - Vincular Usuário ao Grupo </requisitos_afetados>
 * <descricao> Implementação da Interface Responsável Pelas Operações 
 *             de CRUD Referentes a Vinculação de Grupos / Usuários 
 * </descricao>
 * </sumario>
 */
@Repository("grupoUsuarioDAO")
@Lazy(SpringConstants.LAZY_BEANS)
public class GrupoUsuarioDAOImpl implements GrupoUsuarioDAO {

    public static final Long serialVersionUID = 1L;
    
    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public Long salvar(GrupoUsuario value) {
	
        Long id = (Long) getSession().save(value);
	getSession().flush();
        
	return id;
        
    }

    @Override
    public void atualizar(GrupoUsuario value) {
	
        getSession().update(value);
	getSession().flush();
        
    }

    @Override
    public GrupoUsuario obterPorId(Long id) {
	
        return (GrupoUsuario) getSession().get(GrupoUsuario.class, id);
        
    }

    @Override
    public void excluir(GrupoUsuario value) {
	
        desvincularGrupoDosDireitosUsuarios(value);
        value = obterPorId(value.getId());
	getSession().delete(value);
	getSession().flush();
        
    }

    @Override
    public List<GrupoUsuario> obterTodosGruposUsuario() {
	
	List<GrupoUsuario> grupos = this.sessionFactory
		.getCurrentSession()
		.createCriteria(GrupoUsuario.class)
		.addOrder(Order.asc("nome"))
		.list();
	
	for(GrupoUsuario grupo : grupos){
	    Hibernate.initialize(grupo.getDireitosGruposUsuarios());
	    Hibernate.initialize(grupo.getDireitosUsuario());
	}
	
	return grupos;
	
    }

    @Override
    public List<DireitoSistema> recuperarDireitosVinculadosAoGrupo(GrupoUsuario grupo, String sistema) {
	
        String consulta = "select dgu.direitoSistema from DireitoGrupoUsuario dgu "
		+ "where dgu.grupoUsuario = :grupo "
		+ "and dgu.grupoUsuario.sistema = :sistema ";
        
	Query query = getSession().createQuery(consulta);
	query.setParameter("grupo", grupo);
	query.setParameter("sistema", sistema);
        
	return query.list();
        
    }

    @Override
    public List<DireitoSistema> recuperarDireitosNotIn(List<DireitoSistema> direitos, String sistema) {
	
        String consulta  = "select direito from DireitoSistema direito ";
               consulta += "where direito.sistema = :sistema ";
	
        if (direitos != null && !direitos.isEmpty()) {
	    consulta += "and direito not in (:direitos) ";
	}
        
        Query query = getSession().createQuery(consulta);
        query.setParameter("sistema", sistema);
        
	if (direitos != null && !direitos.isEmpty()) {
	    query.setParameterList("direitos", direitos);
	}
        
	return query.list();
        
    }
    
    @Override
    public void salvarAtualizarDireitosGrupo(GrupoUsuario grupo, List<DireitoSistema> direitos){
	
	excluirTodosDireitos(grupo);
	
	for(DireitoSistema direito : direitos){
	    DireitoGrupoUsuario direitoGrupoUsuario = new DireitoGrupoUsuario();
	    direitoGrupoUsuario.setDireitoSistema(direito);
	    direitoGrupoUsuario.setGrupoUsuario(grupo);
	    salvarDireitoGrupoUsuario(direitoGrupoUsuario);
	}
	
    }
    
    private void excluirTodosDireitos(GrupoUsuario grupo){
	
        String delete = "delete from DireitoGrupoUsuario where grupoUsuario = :grupo";
        
	Query query = getSession().createQuery(delete);
	query.setParameter("grupo", grupo);
	query.executeUpdate();
        
    }
    
    private void salvarDireitoGrupoUsuario(DireitoGrupoUsuario direito){
	
        getSession().save(direito);
	getSession().flush();
        
    }
    
    private void desvincularGrupoDosDireitosUsuarios(GrupoUsuario grupo){
	
        String hql = "update DireitoUsuario set grupo = null where grupo = :grupo";
        
	Query query = getSession().createQuery(hql);
	query.setParameter("grupo", grupo);
	query.executeUpdate();
        
    }

    @Override
    public boolean isGrupoJaCadastrado(Long codigo, String sistema) {
	
        String consulta = "select count(id) from GrupoUsuario where id = :codigo";
        
	Query query = getSession().createQuery(consulta);
	query.setParameter("codigo", codigo);
        
	return ((Long) query.uniqueResult()) > 0;
        
    }

    @Override
    public boolean isGrupoJaCadastrado(String nome, String sistema) {
	
        String consulta = "select count(id) from GrupoUsuario where nome = :nome and sistema = :sistema";
        
	Query query = getSession().createQuery(consulta);
	query.setParameter("nome", nome);
	query.setParameter("sistema", sistema);
        
	return ((Long) query.uniqueResult()) > 0;
        
    }
    
    @Override
    public List<GrupoUsuario> obterTodosGruposSemInitialize(){
	
        return this.sessionFactory .getCurrentSession()
                .createCriteria(GrupoUsuario.class)
		.addOrder(Order.asc("nome")).list();
        
        
    }
    
    @Override
    public List<Usuario> obterUsuariosPorNomeGrupo(String nomeGrupo) {
        
        Criteria criteria = getSession().createCriteria(DireitoUsuario.class);
        
        criteria.createAlias("grupo", "grupo");
        criteria.createAlias("usuario", "usuario");
        criteria.setProjection(Projections.property("usuario"));
        criteria.add(Restrictions.ilike("grupo.nome", nomeGrupo, MatchMode.ANYWHERE));
        criteria.addOrder(Order.asc("usuario.login"));
        
        return criteria.list();
                
    }
    
    @Override
    public List<GrupoUsuario> recuperarGruposUsuarioPorSistema(String sistema) {
        
        return getSession().createCriteria(GrupoUsuario.class)
                .add(Restrictions.eq("sistema", sistema))
                .addOrder(Order.asc("nome")).list();
        
    }
    
    public Session getSession(){
	
        return this.sessionFactory.getCurrentSession();
        
    }    
    
}
